package com.xc.pay.weixin.v2;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xc.pay.common.MessageTemplate;
import com.xc.pay.weixin.modal.v3.WxAppV3Modal;
import com.xc.pay.weixin.util.MD5;
import com.xc.pay.weixin.util.WxToolUtil;
import com.xc.pay.weixin.util.XMLUtil;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.jdom2.JDOMException;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * Filename: WeixinAppPay.java <br>
 * Description: 微信APP支付<br>
 *
 * @author: lenovo <br>
 * @version: 1.0 <br>
 */
@Slf4j
public class WeixinAppPay {

  public static void main(String[] args) {
    try {
      WxAppV3Modal modal = new WxAppV3Modal();
      //            modal.setBody("测试商品");
      //            modal.setOut_trade_no("123456120123");
      //            modal.setTotal_fee("888");
      System.out.println(getOrderInfo(modal));
    } catch (IOException | JDOMException e) {
      e.printStackTrace();
    }
  }

  /**
   * @MethodName: getOrderInfo @Description: 微信APP支付
   *
   * @param modal 支付参数实体
   * @return String 支付所需参数
   * @author lenovo
   * @date 2019-12-01
   */
  public static String getOrderInfo(WxAppV3Modal modal) throws IOException, JDOMException {
    // 请求参数
    TreeMap<String, Object> arrays = new TreeMap<>();
    //        arrays.put("appid", modal.getAppId());
    //        arrays.put("body", modal.getBody());
    //        arrays.put("mch_id", modal.getMchId());
    //        arrays.put("nonce_str", WxToolUtil.getNonceStr());
    //        arrays.put("notify_url", modal.getNotify_url());
    //        arrays.put("out_trade_no", modal.getOut_trade_no());
    //        arrays.put("spbill_create_ip", WxToolUtil.getIpAddress());
    //        arrays.put("total_fee",
    // (Double.valueOf(modal.getTotal_fee())*100+"").replace(".0",""));
    arrays.put("trade_type", "APP");
    arrays.put("attach", modal.getAttach());

    // 签名
    //        String sign = SignCreateUtil.createSign(modal.getSecurity(), arrays);
    //         拼接请求参数
    //        arrays.put("sign", sign);
    // 转换请求参数为XML
    String xml = XMLUtil.parseXML(arrays);
    // 请求预付单id
    OkHttpClient client = new OkHttpClient();
    Request requestOkhttp =
        new Request.Builder()
            .url(MessageTemplate.URL)
            .post(RequestBody.create(MediaType.parse("application/xml"), xml))
            .build();
    Call call = client.newCall(requestOkhttp);
    String result = call.execute().body().string();
    // 结果集
    Map<String, String> resultMap = XMLUtil.parseMap(result);
    log.info("统一下单接口返回结果" + result);
    // 取得预付单id
    if (resultMap.containsKey("result_code")
        && resultMap.containsKey("return_code")
        && resultMap.containsKey("prepay_id")) {
      String return_code = resultMap.get("return_code");
      String result_code = resultMap.get("result_code");
      if ("SUCCESS".equals(result_code) && "SUCCESS".equals(return_code)) {
        // 取得prepare_id
        String prepay_id = resultMap.get("prepay_id");
        log.info("prepay_id:{}", prepay_id);
        SortedMap<String, Object> orderInfoMap = new TreeMap<>();
        //                orderInfoMap.put("appid", modal.getAppId());
        //                orderInfoMap.put("partnerid", modal.getMchId());
        orderInfoMap.put("prepayid", prepay_id);
        orderInfoMap.put("noncestr", WxToolUtil.getNonceStr());
        orderInfoMap.put("package", "Sign=WXPay");
        orderInfoMap.put("timestamp", WxToolUtil.getTimestamp());
        //                String sign2 = SignCreateUtil.createSign(modal.getSecurity(),
        // orderInfoMap);
        //                orderInfoMap.put("sign", sign2);
        return JSON.toJSONString(orderInfoMap);
      } else {
        throw new IOException("no result..");
      }
    } else {
      throw new IOException("no result..");
    }
  }

  /**
   * 验证回调签名
   *
   * @return
   */
  public static boolean isTenpaySign(Map<String, String> map) {
    String characterEncoding = "utf-8";
    String charset = "utf-8";
    String signFromAPIResponse = map.get("sign");
    if (signFromAPIResponse == null || signFromAPIResponse.equals("")) {
      System.out.println("API返回的数据签名数据不存在，有可能被第三方篡改!!!");
      return false;
    }
    log.debug("服务器回包里面的签名是:" + signFromAPIResponse);
    // 过滤空 设置 TreeMap
    SortedMap<String, String> packageParams = new TreeMap();

    for (String parameter : map.keySet()) {
      String parameterValue = map.get(parameter);
      String v = "";
      if (null != parameterValue) {
        v = parameterValue.trim();
      }
      packageParams.put(parameter, v);
    }

    StringBuffer sb = new StringBuffer();
    Set es = packageParams.entrySet();
    Iterator it = es.iterator();

    while (it.hasNext()) {
      Map.Entry entry = (Map.Entry) it.next();
      String k = (String) entry.getKey();
      String v = (String) entry.getValue();
      if (!"sign".equals(k) && null != v && !"".equals(v)) {
        sb.append(k + "=" + v + "&");
      }
    }
    // TODO: 2019/1/25 微信支付的key
    //        sb.append("key=" + new WxAppModal().getSecurity());

    // 将API返回的数据根据用签名算法进行计算新的签名，用来跟API返回的签名进行比较
    // 算出签名
    String resultSign = "";
    String tobesign = sb.toString();

    if (null == charset || "".equals(charset)) {
      resultSign = MD5.encode(tobesign).toUpperCase();
    } else {
      try {
        resultSign = MD5.encode(tobesign).toUpperCase();
      } catch (Exception e) {
        resultSign = MD5.encode(tobesign).toUpperCase();
      }
    }

    String tenpaySign = packageParams.get("sign").toUpperCase();
    return tenpaySign.equals(resultSign);
  }

  /**
   * @MethodName: notifyWeiXinPay @Description: 微信支付回调校验
   *
   * @param request 微信返回request
   * @return String 通知微信
   * @author rongrong
   * @date 2019-12-02
   */
  public static Boolean notifyWeiXinPay(HttpServletRequest request)
      throws IOException, JDOMException {
    InputStream inStream = request.getInputStream();
    ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int len;
    while ((len = inStream.read(buffer)) != -1) {
      outSteam.write(buffer, 0, len);
    }
    String resultXml = new String(outSteam.toByteArray(), "utf-8");
    Map<String, String> params = XMLUtil.parseMap(resultXml);
    outSteam.close();
    inStream.close();

    Map<String, String> return_data = new HashMap<>();
    if (!isTenpaySign(params)) {
      // 支付失败
      log.debug("支付回调校验失败==>{}", JSONObject.toJSONString(params));
      return false;
    }
    log.info("===============付款成功==============");
    return true;
  }
}
